﻿#include "libcomm.h"

typedef std::vector<CommType> InnerVector;
#define VECTORINST ((InnerVector*)m_list)
#define VECTORINSTCOPY(rhs)	(*((InnerVector*)m_list) = *((InnerVector*)rhs.m_list))

Array::Array():m_list(NULL)
{
	m_list = new InnerVector();
	MYLIB_ASSERT_NOTNULL(m_list);
}

Array::Array(const Array& rhs):m_list(NULL)
{
	m_list = new InnerVector();
	MYLIB_ASSERT_NOTNULL(m_list);
	VECTORINSTCOPY(rhs);
}

Array& Array::operator=(const Array& rhs)
{
	if(m_list != rhs.m_list)
	{
		VECTORINSTCOPY(rhs);
	}
	return *this;
}

Array::~Array()
{
	if(NULL != m_list)
	{
		delete VECTORINST;
		m_list = NULL;
	}
}


int Array::count() const
{
	return VECTORINST->size();
}

CommType& Array::get(int index)
{
	MYLIB_ASSERT(index>=0 && index<count());
	return VECTORINST->at(index);
}

const CommType& Array::get(int index) const
{
	MYLIB_ASSERT(index>=0 && index<count());
	return VECTORINST->at(index);
}

CommType& Array::operator[](int index)
{
	return get(index);	
}

const CommType& Array::operator[](int index) const
{
	return get(index);
}

Array& Array::append(const CommType& inst)
{
	VECTORINST->push_back(inst);
	return *this;
}

Array& Array::insert(int index, const CommType& inst)
{		
	MYLIB_ASSERT(index>=0 && index<=count());
	InnerVector::iterator itor = VECTORINST->begin();
	for (int i=0;i<index;i++)
		itor++;
	VECTORINST->insert(itor,inst);
	return *this;
}	

Array& Array::remove(int index)
{
	MYLIB_ASSERT(index>=0 && index<count());
	InnerVector::iterator itor = VECTORINST->begin();
	for (int i=0;i<index;i++)
		itor++;
	VECTORINST->erase(itor);
	return *this;
}

Array& Array::clear()
{
	VECTORINST->clear();
	return *this;
}

Array& Array::operator<<(const CommType& inst)
{
	return append(inst);
}

////////////////////////////////////////////////////////////////////////// Arguments

Arguments::operator Buffer() const
{
	return this->Serialize();
}

StringList Arguments::ToStringList() const
{
	StringList strings;
	int count = this->count();
	for (int i=0;i<count;i++)
	{
		const CommType& arg = this->get(i);
		strings.append(arg.ToString());
	}
	return strings;
}

Buffer Arguments::Serialize() const
{
	Buffer buffer;
	int count = this->count();
	for (int i=0;i<count;i++)
	{
		const CommType& arg = this->get(i);
		Buffer item = arg.Serialize();
		unsigned int item_size = 0;
		{
			size_t size = item.size();
			MYLIB_ASSERT(size<=COMMTYPE_MAX_SIZE); 
			item_size = size;
		}
		buffer.append(&item_size,sizeof(item_size));	// item size: 4 bytes.
		buffer.append(item);							// item data.
	}
	return buffer;
}

Arguments Arguments::Deserialize(const void* buffer, size_t sz)
{
	Arguments args;
	const char* ptr = (const char*)buffer;
	size_t total = 0;
	do 
	{
		unsigned int size = 0;
		unsigned int size_size = sizeof(size);

		if(sz - total < size_size)
		{
			LOGERR("%s(line %d) error: invalid buffer header(size:0x%x).",__FUNCTION__,__LINE__,sz-total);
			break;
		}
		memcpy(&size,ptr,size_size);
		if(size > COMMTYPE_MAX_SIZE)
		{
			LOGERR("%s(line %d) error: invalid buffer header(size:0x%x).",__FUNCTION__,__LINE__,size);
			break;
		}

		total += size_size;
		ptr += size_size;

		if(sz - total < size)
		{
			LOGERR("%s(line %d) error: invalid buffer format.",__FUNCTION__,__LINE__);
			break;
		}

		CommType value = CommType::Deserialize(ptr,size);
		if(value.IsError())
		{
			LOGERR("%s(line %d) error.",__FUNCTION__,__LINE__);
			break;
		}

		args.append(value);

		total += size;
		ptr += size;

	} while (total < sz);

	return args;
}

Arguments Arguments::Deserialize(const Buffer& buffer)
{
	return Arguments::Deserialize(buffer.get(),buffer.size());
}
